home *** CD-ROM | disk | FTP | other *** search
/ Aminet 31 / Aminet 31 (1999)(Schatztruhe)[!][Jun 1999].iso / Aminet / dev / c / vbccwossrc.lha / vbcc / pasm / main.c < prev    next >
C/C++ Source or Header  |  1999-03-07  |  9KB  |  311 lines

  1. /* $VER: pasm main.c V0.7 (02.01.98)
  2.  *
  3.  * This file is part of pasm, a portable PowerPC assembler.
  4.  * Copyright (c) 1997-98  Frank Wille
  5.  *
  6.  * pasm is freeware and part of the portable and retargetable ANSI C
  7.  * compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
  8.  * pasm may be freely redistributed as long as no modifications are
  9.  * made and nothing is charged for it. Non-commercial usage is allowed
  10.  * without any restrictions.
  11.  * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
  12.  * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
  13.  *
  14.  *
  15.  * v0.7   (02.01.98) phx
  16.  *        Allow more than two assembler passes, as required for
  17.  *        optimizations.
  18.  *        Option -O (output format) was renamed to -F. New option -O for
  19.  *        enabling optimizations.
  20.  *        Output format 3 is ADOS (like EHF, but doesn't use HUNK_PPC_CODE).
  21.  * v0.6   (30.10.97) phx
  22.  *        Options to disable warnings for optional, 64-bit and super-
  23.  *        visor instructions: -mo, -m64, -ms.
  24.  * v0.5   (12.10.97) phx
  25.  *        Option -D defines symbols. If an '=' is missing, a default
  26.  *        value of '1' will be assigned. Assignment of symbols, which
  27.  *        are defined later in the source, is also allowed.
  28.  * v0.4   (05.07.97) phx
  29.  *        Program returns EXIT_FAILURE if an error occurs.
  30.  *        -V prints only version and build string and no instructions.
  31.  *        Base address for absolute code may be set with -B option.
  32.  *        EHF support.
  33.  *        New option -I to specify some include paths.
  34.  *        Option -x automatically declares unknown symbols as
  35.  *        externally defined.
  36.  * v0.2   (25.03.97) phx
  37.  *        Writes ELF object for 32-bit PowerPC big-endian. Either absolute
  38.  *        or ELF output format may be selected. ELF is default for all
  39.  *        currently supported platforms. PPCasm supports nine different
  40.  *        relocation types (there are much more...).
  41.  *        Compiles and works also under NetBSD/amiga (68k).
  42.  *        Changed function declaration to 'new style' in all sources
  43.  *        (to avoid problems with '...' for example).
  44.  *        Supports multiple output formats. Currently Absolute and ELF.
  45.  * v0.1   (11.03.97) phx
  46.  *        First test version with all PowerPC instructions and most
  47.  *        important directives. Only raw, absolute output.
  48.  * v0.0   (14.02.97) phx
  49.  *        File created. Project started.
  50.  */
  51.  
  52.  
  53. #define MAIN_C
  54. #include "ppcasm.h"
  55.  
  56.  
  57. struct GlobalVars gvars;
  58.  
  59.  
  60. void cleanup(struct GlobalVars *);
  61.  
  62. static char *default_destname(struct GlobalVars *);
  63. static void reset_sections(struct GlobalVars *);
  64. static char *get_option_arg(int,char *[],int *);
  65. static void write_object(struct GlobalVars *);
  66.  
  67.  
  68.  
  69. main(int argc,char *argv[])
  70. {
  71.   struct GlobalVars *gv = &gvars;
  72.   int i,j;
  73.   char *buf;
  74.   char *stdassgn = "1";  /* default assignment for user definitions */
  75.   struct UserDefine *udn;
  76.  
  77.   /* initialize and set default values */
  78.   memset(gv,0,sizeof(struct GlobalVars));
  79.   gv->maxerrors = DEF_MAXERRORS;
  80.   gv->output = OFMT_DEFAULT;  /* default output format */
  81.   initlist(&gv->sourcelist);
  82.   initlist(&gv->sectionlist);
  83.   initlist(&gv->userdeflist);
  84.  
  85.   if (argc<2 || (argc==2 && *argv[1]=='?')) {
  86.     show_usage();
  87.     exit(EXIT_SUCCESS);
  88.   }
  89.   for (i=1; i<argc; i++) {
  90.     if (*argv[i] == '-') {
  91.       /* option detected */
  92.       switch (argv[i][1]) {
  93.  
  94.         case 'V':  /* show version */
  95.           show_version();
  96.           exit(EXIT_SUCCESS);
  97.  
  98.         case 'o':  /* set output file */
  99.           if (!(gv->dest_name = get_option_arg(argc,argv,&i)))
  100.             error(3);  /* missing output file name */
  101.           break;
  102.  
  103.         case 'w':  /* suppress warnings */
  104.           gv->dontwarn = TRUE;
  105.           break;
  106.  
  107.         case 'x':  /* auto extern */
  108.           gv->autoextern = TRUE;
  109.           break;
  110.  
  111.         case 'R':  /* don't predefine register symbols, etc. */
  112.           gv->noregsymbols = TRUE;
  113.           break;
  114.  
  115.         case 'X':  /* no extended mnemonics */
  116.           gv->noextmnemo = TRUE;
  117.           break;
  118.  
  119.         case 'F':  /* set output format (0=abs, 1=elf, 2=ehf, ... ) */
  120.           if (buf = get_option_arg(argc,argv,&i)) {
  121.             if ((j = atoi(buf)) > OFMT_LAST)
  122.               error(49,j);  /* unknown output format */
  123.             else
  124.               gv->output = j;
  125.           }
  126.           else
  127.             error(48,'F');  /* option -F: argument expected */
  128.           break;
  129.  
  130.         case 'O':  /* set optimization level (0=none, ...) */
  131.           if (buf = get_option_arg(argc,argv,&i))
  132.             gv->opt = (uint32)atoi(buf);
  133.           else
  134.             error(48,'O');  /* option -O: argument expected */
  135.           break;
  136.  
  137.         case 'I':  /* add include path */
  138.           for (j=0; j<MAX_INCPATHS; j++) {
  139.             if (gv->incpaths[j] == NULL) {
  140.               if (!(gv->incpaths[j] = get_option_arg(argc,argv,&i)))
  141.                 error(48,'I');  /* option -I: argument expected */
  142.               break;
  143.             }
  144.           }
  145.           if (j >= MAX_INCPATHS)  /* path was ignored */
  146.             error(51,MAX_INCPATHS,get_option_arg(argc,argv,&i));
  147.           break;
  148.  
  149.         case 'B':  /* base address for absolute code */
  150.           if (buf = get_option_arg(argc,argv,&i)) {
  151.             if (!(sscanf(buf,"%li",(long *)&gv->absbase)))
  152.               error(54,'B');  /* option -B: integer expected */
  153.           }
  154.           else
  155.             error(48,'B');  /* option -B: argument expected */
  156.           break;
  157.  
  158.         case 'D':  /* define a symbol */
  159.           if (buf = get_option_arg(argc,argv,&i)) {
  160.             buf = getsymbol(gv,buf);
  161.             if (*gv->strbuf) {
  162.               buf = skipspaces(buf);
  163.               if (*buf == '=')
  164.                 buf = skipspaces(++buf);
  165.               else
  166.                 buf = stdassgn;
  167.               udn = alloc(sizeof(struct UserDefine));
  168.               udn->line = alloc(8 + strlen(gv->strbuf) + strlen(buf));
  169.               sprintf(udn->line,".set %s,%s\n",gv->strbuf,buf);
  170.               addtail(&gv->userdeflist,&udn->n);
  171.             }
  172.             else
  173.               error(56,'D');  /* option -D: symbol name expected */
  174.           }
  175.           else
  176.             error(48,'D');  /* option -D: argument expected */
  177.           break;
  178.  
  179.         case 'm':  /* -m set assembler mode */
  180.           if (buf = get_option_arg(argc,argv,&i)) {
  181.             if (!strcmp(buf,"64")) {
  182.               gv->sixtyfourmode = TRUE;
  183.               break;
  184.             }
  185.             else if (*buf == 'o') {
  186.               gv->optinstrmode = TRUE;
  187.               break;
  188.             }
  189.             else if (*buf == 's') {
  190.               gv->supermode = TRUE;
  191.               break;
  192.             }
  193.           }
  194.           error(57,buf);  /* Unknown assembler mode -mX */
  195.           break;
  196.  
  197.         default:
  198.           printf("Unknown option -%c ignored.\n",argv[i][1]);
  199.           break;
  200.       }
  201.     }
  202.     else {
  203.       /* source file name */
  204.       if (gv->source_name)
  205.         error(4);  /* multiple source file names detected */
  206.       gv->source_name = argv[i];
  207.     }
  208.   }
  209.   if (!gv->source_name)
  210.     error(2);  /* missing source file name */
  211.  
  212.   if (!gv->dest_name)
  213.     gv->dest_name = default_destname(gv);    
  214.  
  215.   /* initialization */
  216.   init_hashtables(gv);
  217.  
  218.   /* assemble */
  219.   exec_pass1(gv);
  220.  
  221.   for (;;) {
  222.     gv->anotherpass = FALSE;
  223.     exec_pass2(gv);
  224.     if (!gv->anotherpass)
  225.       break;
  226.     /* another pass is required! */
  227.     reset_sections(gv);
  228.   }
  229.  
  230.   /* write output file */
  231.   write_object(gv);
  232.   cleanup(gv);
  233. }
  234.  
  235.  
  236. static void reset_sections(struct GlobalVars *gv)
  237. /* free section contents, all xrefs and relocations */
  238. {
  239.   struct Section *nexts,*sec=(struct Section *)gv->sectionlist.first;
  240.   struct node *n;
  241.  
  242.   while (nexts = (struct Section *)sec->n.next) {
  243.     while (n = remhead(&sec->reloclist))
  244.       free(n);
  245.     while (n = remhead(&sec->xreflist))
  246.       free(n);
  247.     if (!(sec->flags & SF_UNINITIALIZED) && sec->contents) {
  248.       free(sec->contents);
  249.       sec->data = sec->contents = NULL;
  250.     }
  251.     sec = nexts;
  252.   }
  253. }
  254.  
  255.  
  256. static char *default_destname(struct GlobalVars *gv)
  257. /* make default output file name from source file name */
  258. {
  259.   char dname[STRBUFSIZE];
  260.   int i;
  261.  
  262.   strncpy(dname,gv->source_name,STRBUFSIZE-1);
  263.   i = strlen(dname